package HBase;

import org.apache.hadoop.hbase.NamespaceDescriptor;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.util.Bytes;
import java.io.IOException;

public class HBaseDDL {

    // 添加静态属性connection指向单例连接
    public static Connection connection = HBaseConnect.connection;

    /**
     * 创建命名空间
     *
     * @param namespace 命名空间名称
     */
    public static void createNamespace(String namespace) throws IOException {
        // 1. 获取admin
        // 此处的异常先不要抛出  等待方法写完  再统一进行处理(因为此处抛出后后续就不会展示异常报错)
        // admin的连接是轻量级的  不是线程安全的  不推荐池化或者缓存这个连接

        Admin admin = connection.getAdmin();

        // 2. 调用方法创建命名空间
        // 代码相对shell更加底层  所以shell能够实现的功能 代码一定能实现
        // 所以需要填写完整的命名空间描述

        // 2.1 创建命令空间描述建造者 => 设计师
        NamespaceDescriptor.Builder builder = NamespaceDescriptor.create(namespace);

        // 2.2 给命令空间添加需求
        builder.addConfiguration("user", "Stan");

        // 2.3 使用builder构造出对应的添加完参数的对象  完成创建
        NamespaceDescriptor build = builder.build();

        // 创建命名空间出现的问题  都属于本方法自身的问题  不应该抛出
        try {
            admin.createNamespace(build);
            System.out.println("命名空间：" + namespace + "创建成功");
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            admin.close();
        }
        // 注意此处未关闭connection连接
    }

    /**
     * 判断表格是否存在
     *
     * @param namespace 命名空间名称
     * @param tableName 表格名称
     * @return ture表示存在
     */
    public static boolean isTableExists(String namespace, String tableName) throws IOException {
        // 1. 获取admin
        Admin admin = connection.getAdmin();

        // 2. 使用方法判断表格是否存在
        boolean flag = false;
        TableName name = TableName.valueOf(namespace, tableName);
        try {
            flag = admin.tableExists(name);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            // 3. 关闭admin
            admin.close();
        }
        // 3. 返回结果
        return flag;
    }

    /**
     * 创建表格
     *
     * @param namespace      命名空间名称
     * @param tableName      表格名称
     * @param columnFamilies 列族名称  可以有多个
     */
    public static void createTable(String namespace, String tableName, String... columnFamilies) throws IOException {
        // 判断是否有至少一个列族
        if (columnFamilies.length == 0) {
            System.out.println("创建表格要求至少有一个列族！");
            return;
        }

        // 判断表格是否存在
        if (isTableExists(namespace, tableName)) {
            System.out.println("表格已经存在~");
            return;
        }

        // 1.获取admin
        Admin admin = connection.getAdmin();

        // 2. 调用方法创建表格
        // 2.1 创建表格描述的建造者
        TableDescriptorBuilder tableDescriptorBuilder = TableDescriptorBuilder.newBuilder(TableName.valueOf(namespace, tableName));

        // 2.2 添加参数
        for (String columnFamily : columnFamilies) {
            // 2.3 创建列族描述的建造者
            ColumnFamilyDescriptorBuilder columnFamilyDescriptorBuilder = ColumnFamilyDescriptorBuilder.newBuilder(columnFamily.getBytes());

            // 2.4 对应当前的列族添加其他参数
            // 添加版本参数
            columnFamilyDescriptorBuilder.setMaxVersions(5);

            // 2.5 创建添加完参数的列族描述
            tableDescriptorBuilder.setColumnFamily(columnFamilyDescriptorBuilder.build());

        }

        // 2.6 创建对应的表格描述
        TableDescriptor tableDescriptor = tableDescriptorBuilder.build();
        try {
            admin.createTable(tableDescriptor);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        // 3. 关闭admin
        admin.close();
    }

    /**
     * 修改表格中一个列族的版本
     *
     * @param namespace    命名空间名称
     * @param tableName    表格名称
     * @param columnFamily 列族名称
     * @param version      版本
     */
    public static void modifyTable(String namespace, String tableName, String columnFamily, int version) throws IOException {
        // 判断表格是否存在
        if (!isTableExists(namespace, tableName)) {
            System.out.println("表格不存在无法修改");
            return;
        }

        // 1. 获取admin
        Admin admin = connection.getAdmin();
        try {
            // 2. 调用方法修改表格
            // 2.0 获取之前的表格描述
            TableDescriptor descriptor = admin.getDescriptor(TableName.valueOf(namespace, tableName));

            // 2.1 创建一个表格描述建造者
            // 如果使用填写tableName的方法  相当于创建了一个新的表格描述建造者  没有之前的信息
            // 如果想要修改之前的信息   必须调用方法填写一个旧的表格描述
            TableDescriptorBuilder tableDescriptorBuilder = TableDescriptorBuilder.newBuilder(descriptor);

            // 2.2 对应建造者进行表格数据的修改
            ColumnFamilyDescriptor columnFamily1 = descriptor.getColumnFamily(Bytes.toBytes(columnFamily));

            // 创建列族描述建造者
            // 需要填写旧的列族描述
            ColumnFamilyDescriptorBuilder columnFamilyDescriptorBuilder = ColumnFamilyDescriptorBuilder.newBuilder(columnFamily1);

            // 修改对应的版本
            columnFamilyDescriptorBuilder.setMaxVersions(version);

            // 此处修改的时候  如果填写的新创建   那么别的参数会初始化
            tableDescriptorBuilder.modifyColumnFamily(columnFamilyDescriptorBuilder.build());

            admin.modifyTable(tableDescriptorBuilder.build());

        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        // 3. 关闭admin
        admin.close();

    }

    /**
     * 删除表格
     *
     * @param namespace 命名空间名称
     * @param tableName 表格名称
     * @return true表示删除成功
     */
    public static boolean deleteTable(String namespace, String tableName) throws IOException {
        // 1. 判断表格是否存在
        if (!isTableExists(namespace, tableName)) {
            System.out.println("表格不存在，咋删？");
            return false;
        }

        // 2. 获取admin
        Admin admin = connection.getAdmin();

        // 3. 调用相关的方法删除表格
        try {
            TableName tableName1 = TableName.valueOf(namespace, tableName);
            // HBase删除表格之前  一定要先标记表格为不可以
            admin.disableTable(tableName1);
            admin.deleteTable(tableName1);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        // 4. 关闭admin
        admin.close();
        return true;
    }

    public static void main(String[] args) throws IOException {
        String namespace = "MyDb", tableName = "firstTable";

        // 测试创建命名空间
        createNamespace(namespace);

        // 测试创建表格API
//        createTable(namespace, tableName, "name", "age");

        // 测试 isTableExist API
//        System.out.println(isTableExists(namespace, tableName));

        // 测试修改表中列族版本号API
//        modifyTable(namespace, tableName, "age", 3);

        // 关闭HBase连接
        HBaseConnect.closeConnection();
    }
}
